aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common_features.mk7
-rw-r--r--docs/_summary.md1
-rw-r--r--docs/feature_joystick.md145
-rw-r--r--drivers/avr/analog.c10
-rw-r--r--keyboards/handwired/onekey/keymaps/joystick/config.h3
-rw-r--r--keyboards/handwired/onekey/keymaps/joystick/keymap.c25
-rw-r--r--keyboards/handwired/onekey/keymaps/joystick/rules.mk1
-rw-r--r--quantum/joystick.c13
-rw-r--r--quantum/joystick.h54
-rw-r--r--quantum/process_keycode/process_joystick.c168
-rw-r--r--quantum/process_keycode/process_joystick.h11
-rw-r--r--quantum/quantum.c3
-rw-r--r--quantum/quantum.h4
-rw-r--r--quantum/quantum_keycodes.h35
-rw-r--r--tmk_core/common/keyboard.c7
-rw-r--r--tmk_core/common/report.h13
-rw-r--r--tmk_core/protocol/chibios/usb_main.c69
-rw-r--r--tmk_core/protocol/lufa/lufa.c67
-rw-r--r--tmk_core/protocol/usb_descriptor.c111
-rw-r--r--tmk_core/protocol/usb_descriptor.h15
20 files changed, 758 insertions, 4 deletions
diff --git a/common_features.mk b/common_features.mk
index 8443a759b..f9fca4669 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -529,3 +529,10 @@ ifeq ($(strip $(AUTO_SHIFT_ENABLE)), yes)
529 OPT_DEFS += -DAUTO_SHIFT_MODIFIERS 529 OPT_DEFS += -DAUTO_SHIFT_MODIFIERS
530 endif 530 endif
531endif 531endif
532
533ifeq ($(strip $(JOYSTICK_ENABLE)), yes)
534 OPT_DEFS += -DJOYSTICK_ENABLE
535 SRC += $(QUANTUM_DIR)/process_keycode/process_joystick.c
536 SRC += $(QUANTUM_DIR)/joystick.c
537 SRC += analog.c
538endif
diff --git a/docs/_summary.md b/docs/_summary.md
index 9ed55a3d0..0c4371215 100644
--- a/docs/_summary.md
+++ b/docs/_summary.md
@@ -103,6 +103,7 @@
103 * [DIP Switch](feature_dip_switch.md) 103 * [DIP Switch](feature_dip_switch.md)
104 * [Encoders](feature_encoders.md) 104 * [Encoders](feature_encoders.md)
105 * [Haptic Feedback](feature_haptic_feedback.md) 105 * [Haptic Feedback](feature_haptic_feedback.md)
106 * [Joystick](feature_joystick.md)
106 * [Proton C Conversion](proton_c_conversion.md) 107 * [Proton C Conversion](proton_c_conversion.md)
107 * [PS/2 Mouse](feature_ps2_mouse.md) 108 * [PS/2 Mouse](feature_ps2_mouse.md)
108 * [Split Keyboard](feature_split_keyboard.md) 109 * [Split Keyboard](feature_split_keyboard.md)
diff --git a/docs/feature_joystick.md b/docs/feature_joystick.md
new file mode 100644
index 000000000..58dfc7b8d
--- /dev/null
+++ b/docs/feature_joystick.md
@@ -0,0 +1,145 @@
1## Joystick
2
3The keyboard can be made to be recognized as a joystick HID device by the operating system.
4
5This is enabled by adding the following to `rules.mk`:
6
7```makefile
8JOYSTICK_ENABLE = yes
9```
10
11!> Joystick support is not currently available on V-USB devices.
12
13The joystick feature provides two services:
14 * reading analog input devices (eg. potentiometers)
15 * sending gamepad HID reports
16
17Both services can be used without the other, depending on whether you just want to read a device but not send gamepad reports (for volume control for instance)
18or send gamepad reports based on values computed by the keyboard.
19
20### Analog Input
21
22An analog device such as a potentiometer found on a gamepad's analog axes is based on a [voltage divider](https://en.wikipedia.org/wiki/Voltage_divider).
23It is composed of three connectors linked to the ground, the power input and power output (usually the middle one). The power output holds the voltage that varies based on the position of the cursor,
24which value will be read using your MCU's [ADC](https://en.wikipedia.org/wiki/Analog-to-digital_converter).
25Depending on which pins are already used by your keyboard's matrix, the rest of the circuit can get a little bit more complicated,
26feeding the power input and ground connection through pins and using diodes to avoid bad interactions with the matrix scanning procedures.
27
28### Configuring the Joystick
29
30By default, two axes and eight buttons are defined. This can be changed in your `config.h`:
31
32```c
33// Max 32
34#define JOYSTICK_BUTTON_COUNT 16
35// Max 6: X, Y, Z, Rx, Ry, Rz
36#define JOYSTICK_AXES_COUNT 3
37```
38
39When defining axes for your joystick, you have to provide a definition array. You can do this from your keymap.c file.
40A joystick will either be read from an input pin that allows the use of the ADC, or can be virtual, so that its value is provided by your code.
41You have to define an array of type ''joystick_config_t'' and of proper size.
42
43There are three ways for your circuit to work with the ADC, that relies on the use of 1, 2 or 3 pins of the MCU:
44 * 1 pin: your analog device is directly connected to your device GND and VCC. The only pin used is the ADC pin of your choice.
45 * 2 pins: your analog device is powered through a pin that allows toggling it on or off. The other pin is used to read the input value through the ADC.
46 * 3 pins: both the power input and ground are connected to pins that must be set to a proper state before reading and restored afterwards.
47
48The configuration of each axis is performed using one of four macros:
49 * `JOYSTICK_AXIS_VIRTUAL`: no ADC reading must be performed, that value will be provided by keyboard/keymap-level code
50 * `JOYSTICK_AXIS_IN(INPUT_PIN, LOW, REST, HIGH)`: a voltage will be read on the provided pin, which must be an ADC-capable pin.
51 * `JOYSTICK_AXIS_IN_OUT(INPUT_PIN, OUTPUT_PIN, LOW, REST, HIGH)`: the provided `OUTPUT_PIN` will be set high before `INPUT_PIN` is read.
52 * `JOYSTICK_AXIS_IN_OUT_GROUND(INPUT_PIN, OUTPUT_PIN, GROUND_PIN, LOW, REST, HIGH)`: the `OUTPUT_PIN` will be set high and `GROUND_PIN` will be set low before reading from `INPUT_PIN`.
53
54In any case where an ADC reading takes place (when `INPUT_PIN` is provided), additional `LOW`, `REST` and `HIGH` parameters are used.
55These implement the calibration of the analog device by defining the range of read values that will be mapped to the lowest, resting position and highest possible value for the axis (-127 to 127).
56In practice, you have to provide the lowest/highest raw ADC reading, and the raw reading at resting position, when no deflection is applied. You can provide inverted `LOW` and `HIGH` to invert the axis.
57
58For instance, an axes configuration can be defined in the following way:
59
60```c
61//joystick config
62joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT] = {
63 [0] = JOYSTICK_AXIS_IN_OUT_GROUND(A4, B0, A7, 900, 575, 285),
64 [1] = JOYSTICK_AXIS_VIRTUAL
65};
66```
67
68When the ADC reads 900 or higher, the returned axis value will be -127, whereas it will be 127 when the ADC reads 285 or lower. Zero is returned when 575 is read.
69
70In this example, the first axis will be read from the `A4` pin while `B0` is set high and `A7` is set low, using `analogReadPin()`, whereas the second axis will not be read.
71
72In order to give a value to the second axis, you can do so in any customizable entry point: as an action, in `process_record_user()` or in `matrix_scan_user()`, or even in `joystick_task()` which is called even when no key has been pressed.
73You assign a value by writing to `joystick_status.axes[axis_index]` a signed 8-bit value (ranging from -127 to 127). Then it is necessary to assign the flag `JS_UPDATED` to `joystick_status.status` in order for an updated HID report to be sent.
74
75The following example writes two axes based on keypad presses, with `KC_P5` as a precision modifier:
76
77```c
78#ifdef JOYSTICK_ENABLE
79static uint8_t precision_val = 70;
80static uint8_t axesFlags = 0;
81enum axes {
82 Precision = 1,
83 Axis1High = 2,
84 Axis1Low = 4,
85 Axis2High = 8,
86 Axis2Low = 16
87};
88#endif
89
90bool process_record_user(uint16_t keycode, keyrecord_t *record) {
91 switch(keycode) {
92#ifdef JOYSTICK_ENABLE
93 // virtual joystick
94# if JOYSTICK_AXES_COUNT > 1
95 case KC_P8:
96 if (record->event.pressed) {
97 axesFlags |= Axis2Low;
98 } else {
99 axesFlags &= ~Axis2Low;
100 }
101 joystick_status.status |= JS_UPDATED;
102 break;
103 case KC_P2:
104 if (record->event.pressed) {
105 axesFlags |= Axis2High;
106 } else {
107 axesFlags &= ~Axis2High;
108 }
109 joystick_status.status |= JS_UPDATED;
110 break;
111# endif
112 case KC_P4:
113 if (record->event.pressed) {
114 axesFlags |= Axis1Low;
115 } else {
116 axesFlags &= ~Axis1Low;
117 }
118 joystick_status.status |= JS_UPDATED;
119 break;
120 case KC_P6:
121 if (record->event.pressed) {
122 axesFlags |= Axis1High;
123 } else {
124 axesFlags &= ~Axis1High;
125 }
126 joystick_status.status |= JS_UPDATED;
127 break;
128 case KC_P5:
129 if (record->event.pressed) {
130 axesFlags |= Precision;
131 } else {
132 axesFlags &= ~Precision;
133 }
134 joystick_status.status |= JS_UPDATED;
135 break;
136#endif
137 }
138 return true;
139}
140```
141
142### Triggering Joystick Buttons
143
144Joystick buttons are normal Quantum keycodes, defined as `JS_BUTTON0` to `JS_BUTTON31`, depending on the number of buttons you have configured.
145To trigger a joystick button, just add the corresponding keycode to your keymap.
diff --git a/drivers/avr/analog.c b/drivers/avr/analog.c
index 9b8397b93..8d299ffdb 100644
--- a/drivers/avr/analog.c
+++ b/drivers/avr/analog.c
@@ -97,10 +97,11 @@ uint8_t pinToMux(pin_t pin) {
97#endif 97#endif
98 // clang-format on 98 // clang-format on
99 } 99 }
100 return 0;
100} 101}
101 102
102int16_t adc_read(uint8_t mux) { 103int16_t adc_read(uint8_t mux) {
103 uint8_t low; 104 uint16_t low;
104 105
105 // Enable ADC and configure prescaler 106 // Enable ADC and configure prescaler
106 ADCSRA = _BV(ADEN) | ADC_PRESCALER; 107 ADCSRA = _BV(ADEN) | ADC_PRESCALER;
@@ -128,5 +129,10 @@ int16_t adc_read(uint8_t mux) {
128 // Must read LSB first 129 // Must read LSB first
129 low = ADCL; 130 low = ADCL;
130 // Must read MSB only once! 131 // Must read MSB only once!
131 return (ADCH << 8) | low; 132 low |= (ADCH << 8);
133
134 // turn off the ADC
135 ADCSRA &= ~(1 << ADEN);
136
137 return low;
132} 138}
diff --git a/keyboards/handwired/onekey/keymaps/joystick/config.h b/keyboards/handwired/onekey/keymaps/joystick/config.h
new file mode 100644
index 000000000..5701d80c8
--- /dev/null
+++ b/keyboards/handwired/onekey/keymaps/joystick/config.h
@@ -0,0 +1,3 @@
1#pragma once
2#define JOYSTICK_AXES_COUNT 2
3#define JOYSTICK_BUTTON_COUNT 1
diff --git a/keyboards/handwired/onekey/keymaps/joystick/keymap.c b/keyboards/handwired/onekey/keymaps/joystick/keymap.c
new file mode 100644
index 000000000..60802f464
--- /dev/null
+++ b/keyboards/handwired/onekey/keymaps/joystick/keymap.c
@@ -0,0 +1,25 @@
1#include QMK_KEYBOARD_H
2
3#include "joystick.h"
4
5#ifndef ADC_PIN
6# define ADC_PIN F6
7#endif
8
9const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
10 LAYOUT( JS_BUTTON0 )
11};
12
13void matrix_scan_user() {
14 int16_t val = (((uint32_t)timer_read()%5000 - 2500) * 255) / 5000;
15 if (val != joystick_status.axes[1]) {
16 joystick_status.axes[1] = val;
17 joystick_status.status |= JS_UPDATED;
18 }
19}
20
21//joystick config
22joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT] = {
23 [0] = JOYSTICK_AXIS_IN(ADC_PIN, 0, 512, 1023)
24 , [1] = JOYSTICK_AXIS_VIRTUAL
25}; \ No newline at end of file
diff --git a/keyboards/handwired/onekey/keymaps/joystick/rules.mk b/keyboards/handwired/onekey/keymaps/joystick/rules.mk
new file mode 100644
index 000000000..fbddbc6de
--- /dev/null
+++ b/keyboards/handwired/onekey/keymaps/joystick/rules.mk
@@ -0,0 +1 @@
JOYSTICK_ENABLE = yes
diff --git a/quantum/joystick.c b/quantum/joystick.c
new file mode 100644
index 000000000..7b87201ae
--- /dev/null
+++ b/quantum/joystick.c
@@ -0,0 +1,13 @@
1#include "joystick.h"
2
3joystick_t joystick_status = {.buttons = {0},
4 .axes =
5 {
6#if JOYSTICK_AXES_COUNT > 0
7 0
8#endif
9 },
10 .status = 0};
11
12// array defining the reading of analog values for each axis
13__attribute__((weak)) joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT] = {};
diff --git a/quantum/joystick.h b/quantum/joystick.h
new file mode 100644
index 000000000..a95472b9f
--- /dev/null
+++ b/quantum/joystick.h
@@ -0,0 +1,54 @@
1#pragma once
2
3#ifndef JOYSTICK_BUTTON_COUNT
4# define JOYSTICK_BUTTON_COUNT 8
5#endif
6
7#ifndef JOYSTICK_AXES_COUNT
8# define JOYSTICK_AXES_COUNT 4
9#endif
10
11#include "quantum.h"
12
13#include <stdint.h>
14
15// configure on input_pin of the joystick_axes array entry to JS_VIRTUAL_AXIS
16// to prevent it from being read from the ADC. This allows outputing forged axis value.
17//
18#define JS_VIRTUAL_AXIS 0xFF
19
20#define JOYSTICK_AXIS_VIRTUAL \
21 { JS_VIRTUAL_AXIS, JS_VIRTUAL_AXIS, JS_VIRTUAL_AXIS, 0, 1023 }
22#define JOYSTICK_AXIS_IN(INPUT_PIN, LOW, REST, HIGH) \
23 { JS_VIRTUAL_AXIS, INPUT_PIN, JS_VIRTUAL_AXIS, LOW, REST, HIGH }
24#define JOYSTICK_AXIS_IN_OUT(INPUT_PIN, OUTPUT_PIN, LOW, REST, HIGH) \
25 { OUTPUT_PIN, INPUT_PIN, JS_VIRTUAL_AXIS, LOW, REST, HIGH }
26#define JOYSTICK_AXIS_IN_OUT_GROUND(INPUT_PIN, OUTPUT_PIN, GROUND_PIN, LOW, REST, HIGH) \
27 { OUTPUT_PIN, INPUT_PIN, GROUND_PIN, LOW, REST, HIGH }
28
29typedef struct {
30 pin_t output_pin;
31 pin_t input_pin;
32 pin_t ground_pin;
33
34 // the AVR ADC offers 10 bit precision, with significant bits on the higher part
35 uint16_t min_digit;
36 uint16_t mid_digit;
37 uint16_t max_digit;
38} joystick_config_t;
39
40extern joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT];
41
42enum joystick_status { JS_INITIALIZED = 1, JS_UPDATED = 2 };
43
44typedef struct {
45 uint8_t buttons[JOYSTICK_BUTTON_COUNT / 8 + 1];
46
47 int16_t axes[JOYSTICK_AXES_COUNT];
48 uint8_t status : 2;
49} joystick_t;
50
51extern joystick_t joystick_status;
52
53// to be implemented in the hid protocol library
54void send_joystick_packet(joystick_t *joystick);
diff --git a/quantum/process_keycode/process_joystick.c b/quantum/process_keycode/process_joystick.c
new file mode 100644
index 000000000..c12f75685
--- /dev/null
+++ b/quantum/process_keycode/process_joystick.c
@@ -0,0 +1,168 @@
1#include "joystick.h"
2#include "process_joystick.h"
3
4#include "analog.h"
5
6#include <string.h>
7#include <math.h>
8
9bool process_joystick_buttons(uint16_t keycode, keyrecord_t *record);
10
11bool process_joystick(uint16_t keycode, keyrecord_t *record) {
12 if (process_joystick_buttons(keycode, record) && (joystick_status.status & JS_UPDATED) > 0) {
13 send_joystick_packet(&joystick_status);
14 joystick_status.status &= ~JS_UPDATED;
15 }
16
17 return true;
18}
19
20__attribute__((weak))
21void joystick_task(void) {
22 if (process_joystick_analogread() && (joystick_status.status & JS_UPDATED)) {
23 send_joystick_packet(&joystick_status);
24 joystick_status.status &= ~JS_UPDATED;
25 }
26}
27
28bool process_joystick_buttons(uint16_t keycode, keyrecord_t *record) {
29 if (keycode < JS_BUTTON0 || keycode > JS_BUTTON_MAX) {
30 return true;
31 } else {
32 if (record->event.pressed) {
33 joystick_status.buttons[(keycode - JS_BUTTON0) / 8] |= 1 << (keycode % 8);
34 } else {
35 joystick_status.buttons[(keycode - JS_BUTTON0) / 8] &= ~(1 << (keycode % 8));
36 }
37
38 joystick_status.status |= JS_UPDATED;
39 }
40
41 return true;
42}
43
44uint16_t savePinState(pin_t pin) {
45#ifdef __AVR__
46 uint8_t pinNumber = pin & 0xF;
47 return ((PORTx_ADDRESS(pin) >> pinNumber) & 0x1) << 1 | ((DDRx_ADDRESS(pin) >> pinNumber) & 0x1);
48#elif defined(PROTOCOL_CHIBIOS)
49 /*
50 The pin configuration is backed up in the following format :
51 bit 15 9 8 7 6 5 4 3 2 1 0
52 |unused|ODR|IDR|PUPDR|OSPEEDR|OTYPER|MODER|
53 */
54 return (( PAL_PORT(pin)->MODER >> (2*PAL_PAD(pin))) & 0x3)
55 | (((PAL_PORT(pin)->OTYPER >> (1*PAL_PAD(pin))) & 0x1) << 2)
56 | (((PAL_PORT(pin)->OSPEEDR >> (2*PAL_PAD(pin))) & 0x3) << 3)
57 | (((PAL_PORT(pin)->PUPDR >> (2*PAL_PAD(pin))) & 0x3) << 5)
58 | (((PAL_PORT(pin)->IDR >> (1*PAL_PAD(pin))) & 0x1) << 7)
59 | (((PAL_PORT(pin)->ODR >> (1*PAL_PAD(pin))) & 0x1) << 8);
60#else
61 return 0;
62#endif
63}
64
65void restorePinState(pin_t pin, uint16_t restoreState) {
66#if defined(PROTOCOL_LUFA)
67 uint8_t pinNumber = pin & 0xF;
68 PORTx_ADDRESS(pin) = (PORTx_ADDRESS(pin) & ~_BV(pinNumber)) | (((restoreState >> 1) & 0x1) << pinNumber);
69 DDRx_ADDRESS(pin) = (DDRx_ADDRESS(pin) & ~_BV(pinNumber)) | ((restoreState & 0x1) << pinNumber);
70#elif defined(PROTOCOL_CHIBIOS)
71 PAL_PORT(pin)->MODER = (PAL_PORT(pin)->MODER & ~(0x3<< (2*PAL_PAD(pin)))) | (restoreState & 0x3) << (2*PAL_PAD(pin));
72 PAL_PORT(pin)->OTYPER = (PAL_PORT(pin)->OTYPER & ~(0x1<< (1*PAL_PAD(pin)))) | ((restoreState>>2) & 0x1) << (1*PAL_PAD(pin));
73 PAL_PORT(pin)->OSPEEDR= (PAL_PORT(pin)->OSPEEDR & ~(0x3<< (2*PAL_PAD(pin)))) | ((restoreState>>3) & 0x3) << (2*PAL_PAD(pin));
74 PAL_PORT(pin)->PUPDR = (PAL_PORT(pin)->PUPDR & ~(0x3<< (2*PAL_PAD(pin)))) | ((restoreState>>5) & 0x3) << (2*PAL_PAD(pin));
75 PAL_PORT(pin)->IDR = (PAL_PORT(pin)->IDR & ~(0x1<< (1*PAL_PAD(pin)))) | ((restoreState>>7) & 0x1) << (1*PAL_PAD(pin));
76 PAL_PORT(pin)->ODR = (PAL_PORT(pin)->ODR & ~(0x1<< (1*PAL_PAD(pin)))) | ((restoreState>>8) & 0x1) << (1*PAL_PAD(pin));
77#else
78 return;
79#endif
80}
81
82__attribute__((weak)) bool process_joystick_analogread() { return process_joystick_analogread_quantum(); }
83
84bool process_joystick_analogread_quantum() {
85#if JOYSTICK_AXES_COUNT > 0
86 for (int axis_index = 0; axis_index < JOYSTICK_AXES_COUNT; ++axis_index) {
87 if (joystick_axes[axis_index].input_pin == JS_VIRTUAL_AXIS) {
88 continue;
89 }
90
91 // save previous input pin status as well
92 uint16_t inputSavedState = savePinState(joystick_axes[axis_index].input_pin);
93
94 // disable pull-up resistor
95 writePinLow(joystick_axes[axis_index].input_pin);
96
97 // if pin was a pull-up input, we need to uncharge it by turning it low
98 // before making it a low input
99 setPinOutput(joystick_axes[axis_index].input_pin);
100
101 wait_us(10);
102
103 // save and apply output pin status
104 uint16_t outputSavedState = 0;
105 if (joystick_axes[axis_index].output_pin != JS_VIRTUAL_AXIS) {
106 // save previous output pin status
107 outputSavedState = savePinState(joystick_axes[axis_index].output_pin);
108
109 setPinOutput(joystick_axes[axis_index].output_pin);
110 writePinHigh(joystick_axes[axis_index].output_pin);
111 }
112
113 uint16_t groundSavedState = 0;
114 if (joystick_axes[axis_index].ground_pin != JS_VIRTUAL_AXIS) {
115 // save previous output pin status
116 groundSavedState = savePinState(joystick_axes[axis_index].ground_pin);
117
118 setPinOutput(joystick_axes[axis_index].ground_pin);
119 writePinLow(joystick_axes[axis_index].ground_pin);
120 }
121
122 wait_us(10);
123
124 setPinInput(joystick_axes[axis_index].input_pin);
125
126 wait_us(10);
127
128# if defined(__AVR__) || defined(PROTOCOL_CHIBIOS)
129 int16_t axis_val = analogReadPin(joystick_axes[axis_index].input_pin);
130# else
131 // default to resting position
132 int16_t axis_val = joystick_axes[axis_index].mid_digit;
133# endif
134
135 //test the converted value against the lower range
136 int32_t ref = joystick_axes[axis_index].mid_digit;
137 int32_t range = joystick_axes[axis_index].min_digit;
138 int32_t ranged_val = ((axis_val - ref) * -127) / (range - ref) ;
139
140 if (ranged_val > 0) {
141 //the value is in the higher range
142 range = joystick_axes[axis_index].max_digit;
143 ranged_val = ((axis_val - ref) * 127) / (range - ref);
144 }
145
146 //clamp the result in the valid range
147 ranged_val = ranged_val < -127 ? -127 : ranged_val;
148 ranged_val = ranged_val > 127 ? 127 : ranged_val;
149
150 if (ranged_val != joystick_status.axes[axis_index]) {
151 joystick_status.axes[axis_index] = ranged_val;
152 joystick_status.status |= JS_UPDATED;
153 }
154
155 // restore output, ground and input status
156 if (joystick_axes[axis_index].output_pin != JS_VIRTUAL_AXIS) {
157 restorePinState(joystick_axes[axis_index].output_pin, outputSavedState);
158 }
159 if (joystick_axes[axis_index].ground_pin != JS_VIRTUAL_AXIS) {
160 restorePinState(joystick_axes[axis_index].ground_pin, groundSavedState);
161 }
162
163 restorePinState(joystick_axes[axis_index].input_pin, inputSavedState);
164 }
165
166#endif
167 return true;
168}
diff --git a/quantum/process_keycode/process_joystick.h b/quantum/process_keycode/process_joystick.h
new file mode 100644
index 000000000..7a8b82913
--- /dev/null
+++ b/quantum/process_keycode/process_joystick.h
@@ -0,0 +1,11 @@
1#pragma once
2
3#include <stdint.h>
4#include "quantum.h"
5
6bool process_joystick(uint16_t keycode, keyrecord_t *record);
7
8void joystick_task(void);
9
10bool process_joystick_analogread(void);
11bool process_joystick_analogread_quantum(void);
diff --git a/quantum/quantum.c b/quantum/quantum.c
index 9d63f4de2..dab6c9172 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -277,6 +277,9 @@ bool process_record_quantum(keyrecord_t *record) {
277#if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE) 277#if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE)
278 process_rgb(keycode, record) && 278 process_rgb(keycode, record) &&
279#endif 279#endif
280#ifdef JOYSTICK_ENABLE
281 process_joystick(keycode, record) &&
282#endif
280 true)) { 283 true)) {
281 return false; 284 return false;
282 } 285 }
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 51deac0cd..a2c0ec9a2 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -142,6 +142,10 @@ extern layer_state_t layer_state;
142# include "process_magic.h" 142# include "process_magic.h"
143#endif 143#endif
144 144
145#ifdef JOYSTICK_ENABLE
146# include "process_joystick.h"
147#endif
148
145#ifdef GRAVE_ESC_ENABLE 149#ifdef GRAVE_ESC_ENABLE
146# include "process_grave_esc.h" 150# include "process_grave_esc.h"
147#endif 151#endif
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
index 437921aeb..5e7c9ad33 100644
--- a/quantum/quantum_keycodes.h
+++ b/quantum/quantum_keycodes.h
@@ -512,6 +512,41 @@ enum quantum_keycodes {
512 DYN_MACRO_PLAY1, 512 DYN_MACRO_PLAY1,
513 DYN_MACRO_PLAY2, 513 DYN_MACRO_PLAY2,
514 514
515 JS_BUTTON0,
516 JS_BUTTON_MIN = JS_BUTTON0,
517 JS_BUTTON1,
518 JS_BUTTON2,
519 JS_BUTTON3,
520 JS_BUTTON4,
521 JS_BUTTON5,
522 JS_BUTTON6,
523 JS_BUTTON7,
524 JS_BUTTON8,
525 JS_BUTTON9,
526 JS_BUTTON10,
527 JS_BUTTON11,
528 JS_BUTTON12,
529 JS_BUTTON13,
530 JS_BUTTON14,
531 JS_BUTTON15,
532 JS_BUTTON16,
533 JS_BUTTON17,
534 JS_BUTTON18,
535 JS_BUTTON19,
536 JS_BUTTON20,
537 JS_BUTTON21,
538 JS_BUTTON22,
539 JS_BUTTON23,
540 JS_BUTTON24,
541 JS_BUTTON25,
542 JS_BUTTON26,
543 JS_BUTTON27,
544 JS_BUTTON28,
545 JS_BUTTON29,
546 JS_BUTTON30,
547 JS_BUTTON31,
548 JS_BUTTON_MAX = JS_BUTTON31,
549
515 // always leave at the end 550 // always leave at the end
516 SAFE_RANGE 551 SAFE_RANGE
517}; 552};
diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c
index 714c3d048..a45af56df 100644
--- a/tmk_core/common/keyboard.c
+++ b/tmk_core/common/keyboard.c
@@ -74,6 +74,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
74#ifdef MIDI_ENABLE 74#ifdef MIDI_ENABLE
75# include "process_midi.h" 75# include "process_midi.h"
76#endif 76#endif
77#ifdef JOYSTICK_ENABLE
78# include "process_joystick.h"
79#endif
77#ifdef HD44780_ENABLE 80#ifdef HD44780_ENABLE
78# include "hd44780.h" 81# include "hd44780.h"
79#endif 82#endif
@@ -420,6 +423,10 @@ MATRIX_LOOP_END:
420 } 423 }
421#endif 424#endif
422 425
426#ifdef JOYSTICK_ENABLE
427 joystick_task();
428#endif
429
423 // update LED 430 // update LED
424 if (led_status != host_keyboard_leds()) { 431 if (led_status != host_keyboard_leds()) {
425 led_status = host_keyboard_leds(); 432 led_status = host_keyboard_leds();
diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h
index 1b2f13bdd..1aa33c998 100644
--- a/tmk_core/common/report.h
+++ b/tmk_core/common/report.h
@@ -29,7 +29,8 @@ enum hid_report_ids {
29 REPORT_ID_MOUSE, 29 REPORT_ID_MOUSE,
30 REPORT_ID_SYSTEM, 30 REPORT_ID_SYSTEM,
31 REPORT_ID_CONSUMER, 31 REPORT_ID_CONSUMER,
32 REPORT_ID_NKRO 32 REPORT_ID_NKRO,
33 REPORT_ID_JOYSTICK
33}; 34};
34 35
35/* Mouse buttons */ 36/* Mouse buttons */
@@ -189,6 +190,16 @@ typedef struct {
189 int8_t h; 190 int8_t h;
190} __attribute__((packed)) report_mouse_t; 191} __attribute__((packed)) report_mouse_t;
191 192
193typedef struct {
194#if JOYSTICK_AXES_COUNT > 0
195 int8_t axes[JOYSTICK_AXES_COUNT];
196#endif
197
198#if JOYSTICK_BUTTON_COUNT > 0
199 uint8_t buttons[(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1];
200#endif
201} __attribute__((packed)) joystick_report_t;
202
192/* keycode to system usage */ 203/* keycode to system usage */
193static inline uint16_t KEYCODE2SYSTEM(uint8_t key) { 204static inline uint16_t KEYCODE2SYSTEM(uint8_t key) {
194 switch (key) { 205 switch (key) {
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c
index 21e9f14e5..68c61cf55 100644
--- a/tmk_core/protocol/chibios/usb_main.c
+++ b/tmk_core/protocol/chibios/usb_main.c
@@ -47,6 +47,10 @@
47extern keymap_config_t keymap_config; 47extern keymap_config_t keymap_config;
48#endif 48#endif
49 49
50#ifdef JOYSTICK_ENABLE
51# include "joystick.h"
52#endif
53
50/* --------------------------------------------------------- 54/* ---------------------------------------------------------
51 * Global interface variables and declarations 55 * Global interface variables and declarations
52 * --------------------------------------------------------- 56 * ---------------------------------------------------------
@@ -247,6 +251,9 @@ typedef struct {
247#ifdef VIRTSER_ENABLE 251#ifdef VIRTSER_ENABLE
248 usb_driver_config_t serial_driver; 252 usb_driver_config_t serial_driver;
249#endif 253#endif
254#ifdef JOYSTICK_ENABLE
255 usb_driver_config_t joystick_driver;
256#endif
250 }; 257 };
251 usb_driver_config_t array[0]; 258 usb_driver_config_t array[0];
252 }; 259 };
@@ -283,6 +290,14 @@ static usb_driver_configs_t drivers = {
283# define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK 290# define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK
284 .serial_driver = QMK_USB_DRIVER_CONFIG(CDC, CDC_NOTIFICATION_EPNUM, false), 291 .serial_driver = QMK_USB_DRIVER_CONFIG(CDC, CDC_NOTIFICATION_EPNUM, false),
285#endif 292#endif
293
294#ifdef JOYSTICK_ENABLE
295# define JOYSTICK_IN_CAPACITY 4
296# define JOYSTICK_OUT_CAPACITY 4
297# define JOYSTICK_IN_MODE USB_EP_MODE_TYPE_BULK
298# define JOYSTICK_OUT_MODE USB_EP_MODE_TYPE_BULK
299 .joystick_driver = QMK_USB_DRIVER_CONFIG(JOYSTICK, 0, false),
300#endif
286}; 301};
287 302
288#define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t)) 303#define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t))
@@ -867,3 +882,57 @@ void virtser_task(void) {
867} 882}
868 883
869#endif 884#endif
885
886#ifdef JOYSTICK_ENABLE
887
888void send_joystick_packet(joystick_t *joystick) {
889 joystick_report_t rep = {
890# if JOYSTICK_AXES_COUNT > 0
891 .axes = {joystick->axes[0],
892
893# if JOYSTICK_AXES_COUNT >= 2
894 joystick->axes[1],
895# endif
896# if JOYSTICK_AXES_COUNT >= 3
897 joystick->axes[2],
898# endif
899# if JOYSTICK_AXES_COUNT >= 4
900 joystick->axes[3],
901# endif
902# if JOYSTICK_AXES_COUNT >= 5
903 joystick->axes[4],
904# endif
905# if JOYSTICK_AXES_COUNT >= 6
906 joystick->axes[5],
907# endif
908 },
909# endif // JOYSTICK_AXES_COUNT>0
910
911# if JOYSTICK_BUTTON_COUNT > 0
912 .buttons = {joystick->buttons[0],
913
914# if JOYSTICK_BUTTON_COUNT > 8
915 joystick->buttons[1],
916# endif
917# if JOYSTICK_BUTTON_COUNT > 16
918 joystick->buttons[2],
919# endif
920# if JOYSTICK_BUTTON_COUNT > 24
921 joystick->buttons[3],
922# endif
923 }
924# endif // JOYSTICK_BUTTON_COUNT>0
925 };
926
927 // chnWrite(&drivers.joystick_driver.driver, (uint8_t *)&rep, sizeof(rep));
928 osalSysLock();
929 if (usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
930 osalSysUnlock();
931 return;
932 }
933
934 usbStartTransmitI(&USB_DRIVER, JOYSTICK_IN_EPNUM, (uint8_t *)&rep, sizeof(joystick_report_t));
935 osalSysUnlock();
936}
937
938#endif
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index 6776a964e..85603646d 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -85,6 +85,10 @@ extern keymap_config_t keymap_config;
85# include "raw_hid.h" 85# include "raw_hid.h"
86#endif 86#endif
87 87
88#ifdef JOYSTICK_ENABLE
89# include "joystick.h"
90#endif
91
88uint8_t keyboard_idle = 0; 92uint8_t keyboard_idle = 0;
89/* 0: Boot Protocol, 1: Report Protocol(default) */ 93/* 0: Boot Protocol, 1: Report Protocol(default) */
90uint8_t keyboard_protocol = 1; 94uint8_t keyboard_protocol = 1;
@@ -264,6 +268,66 @@ static void Console_Task(void) {
264#endif 268#endif
265 269
266/******************************************************************************* 270/*******************************************************************************
271 * Joystick
272 ******************************************************************************/
273#ifdef JOYSTICK_ENABLE
274void send_joystick_packet(joystick_t *joystick) {
275 uint8_t timeout = 255;
276
277 joystick_report_t r = {
278# if JOYSTICK_AXES_COUNT > 0
279 .axes = {joystick->axes[0],
280
281# if JOYSTICK_AXES_COUNT >= 2
282 joystick->axes[1],
283# endif
284# if JOYSTICK_AXES_COUNT >= 3
285 joystick->axes[2],
286# endif
287# if JOYSTICK_AXES_COUNT >= 4
288 joystick->axes[3],
289# endif
290# if JOYSTICK_AXES_COUNT >= 5
291 joystick->axes[4],
292# endif
293# if JOYSTICK_AXES_COUNT >= 6
294 joystick->axes[5],
295# endif
296 },
297# endif // JOYSTICK_AXES_COUNT>0
298
299# if JOYSTICK_BUTTON_COUNT > 0
300 .buttons = {joystick->buttons[0],
301
302# if JOYSTICK_BUTTON_COUNT > 8
303 joystick->buttons[1],
304# endif
305# if JOYSTICK_BUTTON_COUNT > 16
306 joystick->buttons[2],
307# endif
308# if JOYSTICK_BUTTON_COUNT > 24
309 joystick->buttons[3],
310# endif
311 }
312# endif // JOYSTICK_BUTTON_COUNT>0
313 };
314
315 /* Select the Joystick Report Endpoint */
316 Endpoint_SelectEndpoint(JOYSTICK_IN_EPNUM);
317
318 /* Check if write ready for a polling interval around 10ms */
319 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
320 if (!Endpoint_IsReadWriteAllowed()) return;
321
322 /* Write Joystick Report Data */
323 Endpoint_Write_Stream_LE(&r, sizeof(joystick_report_t), NULL);
324
325 /* Finalize the stream transfer to send the last packet */
326 Endpoint_ClearIN();
327}
328#endif
329
330/*******************************************************************************
267 * USB Events 331 * USB Events
268 ******************************************************************************/ 332 ******************************************************************************/
269/* 333/*
@@ -411,6 +475,9 @@ void EVENT_USB_Device_ConfigurationChanged(void) {
411 ConfigSuccess &= Endpoint_ConfigureEndpoint((CDC_OUT_EPNUM | ENDPOINT_DIR_OUT), EP_TYPE_BULK, CDC_EPSIZE, 1); 475 ConfigSuccess &= Endpoint_ConfigureEndpoint((CDC_OUT_EPNUM | ENDPOINT_DIR_OUT), EP_TYPE_BULK, CDC_EPSIZE, 1);
412 ConfigSuccess &= Endpoint_ConfigureEndpoint((CDC_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_BULK, CDC_EPSIZE, 1); 476 ConfigSuccess &= Endpoint_ConfigureEndpoint((CDC_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_BULK, CDC_EPSIZE, 1);
413#endif 477#endif
478#ifdef JOYSTICK_ENABLE
479 ConfigSuccess &= ENDPOINT_CONFIG(JOYSTICK_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, JOYSTICK_EPSIZE, ENDPOINT_BANK_SINGLE);
480#endif
414} 481}
415 482
416/* FIXME: Expose this table in the docs somehow 483/* FIXME: Expose this table in the docs somehow
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index bcca24586..f5d32445d 100644
--- a/tmk_core/protocol/usb_descriptor.c
+++ b/tmk_core/protocol/usb_descriptor.c
@@ -279,6 +279,63 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] = {
279}; 279};
280#endif 280#endif
281 281
282#ifdef JOYSTICK_ENABLE
283# if JOYSTICK_AXES_COUNT == 0 && JOYSTICK_BUTTON_COUNT == 0
284# error Need at least one axis or button for joystick
285# endif
286const USB_Descriptor_HIDReport_Datatype_t PROGMEM JoystickReport[] = {
287 HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
288 HID_RI_USAGE(8, 0x04), // Joystick
289 HID_RI_COLLECTION(8, 0x01), // Application
290 HID_RI_COLLECTION(8, 0x00), // Physical
291 HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
292# if JOYSTICK_AXES_COUNT >= 1
293 HID_RI_USAGE(8, 0x30), // X
294# endif
295# if JOYSTICK_AXES_COUNT >= 2
296 HID_RI_USAGE(8, 0x31), // Y
297# endif
298# if JOYSTICK_AXES_COUNT >= 3
299 HID_RI_USAGE(8, 0x32), // Z
300# endif
301# if JOYSTICK_AXES_COUNT >= 4
302 HID_RI_USAGE(8, 0x33), // Rx
303# endif
304# if JOYSTICK_AXES_COUNT >= 5
305 HID_RI_USAGE(8, 0x34), // Ry
306# endif
307# if JOYSTICK_AXES_COUNT >= 6
308 HID_RI_USAGE(8, 0x35), // Rz
309# endif
310# if JOYSTICK_AXES_COUNT >= 1
311 HID_RI_LOGICAL_MINIMUM(8, -127),
312 HID_RI_LOGICAL_MAXIMUM(8, 127),
313 HID_RI_REPORT_COUNT(8, JOYSTICK_AXES_COUNT),
314 HID_RI_REPORT_SIZE(8, 0x08),
315 HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
316# endif
317
318# if JOYSTICK_BUTTON_COUNT >= 1
319 HID_RI_USAGE_PAGE(8, 0x09), // Button
320 HID_RI_USAGE_MINIMUM(8, 0x01),
321 HID_RI_USAGE_MAXIMUM(8, JOYSTICK_BUTTON_COUNT),
322 HID_RI_LOGICAL_MINIMUM(8, 0x00),
323 HID_RI_LOGICAL_MAXIMUM(8, 0x01),
324 HID_RI_REPORT_COUNT(8, JOYSTICK_BUTTON_COUNT),
325 HID_RI_REPORT_SIZE(8, 0x01),
326 HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
327
328# if (JOYSTICK_BUTTON_COUNT % 8) != 0
329 HID_RI_REPORT_COUNT(8, 8 - (JOYSTICK_BUTTON_COUNT % 8)),
330 HID_RI_REPORT_SIZE(8, 0x01),
331 HID_RI_INPUT(8, HID_IOF_CONSTANT),
332# endif
333# endif
334 HID_RI_END_COLLECTION(0),
335 HID_RI_END_COLLECTION(0)
336};
337#endif
338
282/* 339/*
283 * Device descriptor 340 * Device descriptor
284 */ 341 */
@@ -288,7 +345,7 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = {
288 .Type = DTYPE_Device 345 .Type = DTYPE_Device
289 }, 346 },
290 .USBSpecification = VERSION_BCD(1, 1, 0), 347 .USBSpecification = VERSION_BCD(1, 1, 0),
291 348
292#if VIRTSER_ENABLE 349#if VIRTSER_ENABLE
293 .Class = USB_CSCP_IADDeviceClass, 350 .Class = USB_CSCP_IADDeviceClass,
294 .SubClass = USB_CSCP_IADDeviceSubclass, 351 .SubClass = USB_CSCP_IADDeviceSubclass,
@@ -813,6 +870,46 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = {
813 .PollingIntervalMS = 0x05 870 .PollingIntervalMS = 0x05
814 }, 871 },
815#endif 872#endif
873
874 /*
875 * Joystick
876 */
877#ifdef JOYSTICK_ENABLE
878 .Joystick_Interface = {
879 .Header = {
880 .Size = sizeof(USB_Descriptor_Interface_t),
881 .Type = DTYPE_Interface
882 },
883 .InterfaceNumber = JOYSTICK_INTERFACE,
884 .AlternateSetting = 0x00,
885 .TotalEndpoints = 1,
886 .Class = HID_CSCP_HIDClass,
887 .SubClass = HID_CSCP_NonBootSubclass,
888 .Protocol = HID_CSCP_NonBootProtocol,
889 .InterfaceStrIndex = NO_DESCRIPTOR
890 },
891 .Joystick_HID = {
892 .Header = {
893 .Size = sizeof(USB_HID_Descriptor_HID_t),
894 .Type = HID_DTYPE_HID
895 },
896 .HIDSpec = VERSION_BCD(1, 1, 1),
897 .CountryCode = 0x00,
898 .TotalReportDescriptors = 1,
899 .HIDReportType = HID_DTYPE_Report,
900 .HIDReportLength = sizeof(JoystickReport)
901 },
902 .Joystick_INEndpoint = {
903 .Header = {
904 .Size = sizeof(USB_Descriptor_Endpoint_t),
905 .Type = DTYPE_Endpoint
906 },
907 .EndpointAddress = (ENDPOINT_DIR_IN | JOYSTICK_IN_EPNUM),
908 .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
909 .EndpointSize = JOYSTICK_EPSIZE,
910 .PollingIntervalMS = USB_POLLING_INTERVAL_MS
911 }
912#endif
816}; 913};
817 914
818/* 915/*
@@ -945,6 +1042,12 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
945 1042
946 break; 1043 break;
947#endif 1044#endif
1045#ifdef JOYSTICK_ENABLE
1046 case JOYSTICK_INTERFACE:
1047 Address = &ConfigurationDescriptor.Joystick_HID;
1048 Size = sizeof(USB_HID_Descriptor_HID_t);
1049 break;
1050#endif
948 } 1051 }
949 1052
950 break; 1053 break;
@@ -989,6 +1092,12 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
989 1092
990 break; 1093 break;
991#endif 1094#endif
1095#ifdef JOYSTICK_ENABLE
1096 case JOYSTICK_INTERFACE:
1097 Address = &JoystickReport;
1098 Size = sizeof(JoystickReport);
1099 break;
1100#endif
992 } 1101 }
993 1102
994 break; 1103 break;
diff --git a/tmk_core/protocol/usb_descriptor.h b/tmk_core/protocol/usb_descriptor.h
index 34a85978a..79dd87014 100644
--- a/tmk_core/protocol/usb_descriptor.h
+++ b/tmk_core/protocol/usb_descriptor.h
@@ -123,6 +123,13 @@ typedef struct {
123 USB_Descriptor_Endpoint_t CDC_DataOutEndpoint; 123 USB_Descriptor_Endpoint_t CDC_DataOutEndpoint;
124 USB_Descriptor_Endpoint_t CDC_DataInEndpoint; 124 USB_Descriptor_Endpoint_t CDC_DataInEndpoint;
125#endif 125#endif
126
127#ifdef JOYSTICK_ENABLE
128 // Joystick HID Interface
129 USB_Descriptor_Interface_t Joystick_Interface;
130 USB_HID_Descriptor_HID_t Joystick_HID;
131 USB_Descriptor_Endpoint_t Joystick_INEndpoint;
132#endif
126} USB_Descriptor_Configuration_t; 133} USB_Descriptor_Configuration_t;
127 134
128/* 135/*
@@ -164,6 +171,9 @@ enum usb_interfaces {
164 CDI_INTERFACE, 171 CDI_INTERFACE,
165#endif 172#endif
166 173
174#if defined(JOYSTICK_ENABLE)
175 JOYSTICK_INTERFACE,
176#endif
167 TOTAL_INTERFACES 177 TOTAL_INTERFACES
168}; 178};
169 179
@@ -219,6 +229,10 @@ enum usb_endpoints {
219 CDC_IN_EPNUM = NEXT_EPNUM, 229 CDC_IN_EPNUM = NEXT_EPNUM,
220 CDC_OUT_EPNUM = NEXT_EPNUM, 230 CDC_OUT_EPNUM = NEXT_EPNUM,
221#endif 231#endif
232#ifdef JOYSTICK_ENABLE
233 JOYSTICK_IN_EPNUM = NEXT_EPNUM,
234 JOYSTICK_OUT_EPNUM = NEXT_EPNUM,
235#endif
222}; 236};
223 237
224#ifdef PROTOCOL_LUFA 238#ifdef PROTOCOL_LUFA
@@ -243,6 +257,7 @@ enum usb_endpoints {
243#define MIDI_STREAM_EPSIZE 64 257#define MIDI_STREAM_EPSIZE 64
244#define CDC_NOTIFICATION_EPSIZE 8 258#define CDC_NOTIFICATION_EPSIZE 8
245#define CDC_EPSIZE 16 259#define CDC_EPSIZE 16
260#define JOYSTICK_EPSIZE 8
246 261
247uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const void** const DescriptorAddress); 262uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const void** const DescriptorAddress);
248#endif 263#endif