From 1e95f7be8f214c544bf99f415916a4a5f07a1e9b Mon Sep 17 00:00:00 2001 From: Ryan Date: Sun, 27 Nov 2022 03:14:45 +1100 Subject: Joystick feature improvements (#19052) --- quantum/joystick.c | 55 ++++++++++++++++++++------------------ quantum/joystick.h | 77 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 86 insertions(+), 46 deletions(-) (limited to 'quantum') diff --git a/quantum/joystick.c b/quantum/joystick.c index d285dcdb5e..057a018dff 100644 --- a/quantum/joystick.c +++ b/quantum/joystick.c @@ -19,45 +19,48 @@ #include "analog.h" #include "wait.h" -// clang-format off -joystick_t joystick_status = { +joystick_t joystick_state = { .buttons = {0}, - .axes = { -#if JOYSTICK_AXES_COUNT > 0 - 0 + .axes = + { +#if JOYSTICK_AXIS_COUNT > 0 + 0 #endif - }, - .status = 0 + }, + .dirty = false, }; -// clang-format on // array defining the reading of analog values for each axis -__attribute__((weak)) joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT] = {}; +__attribute__((weak)) joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT] = {}; __attribute__((weak)) void joystick_task(void) { joystick_read_axes(); } void joystick_flush(void) { - if ((joystick_status.status & JS_UPDATED) > 0) { - host_joystick_send(&joystick_status); - joystick_status.status &= ~JS_UPDATED; + if (joystick_state.dirty) { + host_joystick_send(&joystick_state); + joystick_state.dirty = false; } } void register_joystick_button(uint8_t button) { - joystick_status.buttons[button / 8] |= 1 << (button % 8); - joystick_status.status |= JS_UPDATED; + if (button >= JOYSTICK_BUTTON_COUNT) return; + joystick_state.buttons[button / 8] |= 1 << (button % 8); + joystick_state.dirty = true; joystick_flush(); } void unregister_joystick_button(uint8_t button) { - joystick_status.buttons[button / 8] &= ~(1 << (button % 8)); - joystick_status.status |= JS_UPDATED; + if (button >= JOYSTICK_BUTTON_COUNT) return; + joystick_state.buttons[button / 8] &= ~(1 << (button % 8)); + joystick_state.dirty = true; joystick_flush(); } int16_t joystick_read_axis(uint8_t axis) { + if (axis >= JOYSTICK_AXIS_COUNT) return 0; + // disable pull-up resistor writePinLow(joystick_axes[axis].input_pin); @@ -93,24 +96,24 @@ int16_t joystick_read_axis(uint8_t axis) { // test the converted value against the lower range int32_t ref = joystick_axes[axis].mid_digit; int32_t range = joystick_axes[axis].min_digit; - int32_t ranged_val = ((axis_val - ref) * -JOYSTICK_RESOLUTION) / (range - ref); + int32_t ranged_val = ((axis_val - ref) * -JOYSTICK_MAX_VALUE) / (range - ref); if (ranged_val > 0) { // the value is in the higher range range = joystick_axes[axis].max_digit; - ranged_val = ((axis_val - ref) * JOYSTICK_RESOLUTION) / (range - ref); + ranged_val = ((axis_val - ref) * JOYSTICK_MAX_VALUE) / (range - ref); } // clamp the result in the valid range - ranged_val = ranged_val < -JOYSTICK_RESOLUTION ? -JOYSTICK_RESOLUTION : ranged_val; - ranged_val = ranged_val > JOYSTICK_RESOLUTION ? JOYSTICK_RESOLUTION : ranged_val; + ranged_val = ranged_val < -JOYSTICK_MAX_VALUE ? -JOYSTICK_MAX_VALUE : ranged_val; + ranged_val = ranged_val > JOYSTICK_MAX_VALUE ? JOYSTICK_MAX_VALUE : ranged_val; return ranged_val; } void joystick_read_axes() { -#if JOYSTICK_AXES_COUNT > 0 - for (int i = 0; i < JOYSTICK_AXES_COUNT; ++i) { +#if JOYSTICK_AXIS_COUNT > 0 + for (int i = 0; i < JOYSTICK_AXIS_COUNT; ++i) { if (joystick_axes[i].input_pin == JS_VIRTUAL_AXIS) { continue; } @@ -123,8 +126,10 @@ void joystick_read_axes() { } void joystick_set_axis(uint8_t axis, int16_t value) { - if (value != joystick_status.axes[axis]) { - joystick_status.axes[axis] = value; - joystick_status.status |= JS_UPDATED; + if (axis >= JOYSTICK_AXIS_COUNT) return; + + if (value != joystick_state.axes[axis]) { + joystick_state.axes[axis] = value; + joystick_state.dirty = true; } } diff --git a/quantum/joystick.h b/quantum/joystick.h index ee966fdb1a..0ac99aa590 100644 --- a/quantum/joystick.h +++ b/quantum/joystick.h @@ -16,32 +16,41 @@ #pragma once +#include #include + #include "gpio.h" +/** + * \defgroup joystick + * + * HID Joystick + * \{ + */ + #ifndef JOYSTICK_BUTTON_COUNT # define JOYSTICK_BUTTON_COUNT 8 #elif JOYSTICK_BUTTON_COUNT > 32 # error Joystick feature only supports up to 32 buttons #endif -#ifndef JOYSTICK_AXES_COUNT -# define JOYSTICK_AXES_COUNT 4 -#elif JOYSTICK_AXES_COUNT > 6 +#ifndef JOYSTICK_AXIS_COUNT +# define JOYSTICK_AXIS_COUNT 2 +#elif JOYSTICK_AXIS_COUNT > 6 # error Joystick feature only supports up to 6 axes #endif -#if JOYSTICK_AXES_COUNT == 0 && JOYSTICK_BUTTON_COUNT == 0 +#if JOYSTICK_AXIS_COUNT == 0 && JOYSTICK_BUTTON_COUNT == 0 # error Joystick feature requires at least one axis or button #endif -#ifndef JOYSTICK_AXES_RESOLUTION -# define JOYSTICK_AXES_RESOLUTION 8 -#elif JOYSTICK_AXES_RESOLUTION < 8 || JOYSTICK_AXES_RESOLUTION > 16 -# error JOYSTICK_AXES_RESOLUTION must be between 8 and 16 +#ifndef JOYSTICK_AXIS_RESOLUTION +# define JOYSTICK_AXIS_RESOLUTION 8 +#elif JOYSTICK_AXIS_RESOLUTION < 8 || JOYSTICK_AXIS_RESOLUTION > 16 +# error JOYSTICK_AXIS_RESOLUTION must be between 8 and 16 #endif -#define JOYSTICK_RESOLUTION ((1L << (JOYSTICK_AXES_RESOLUTION - 1)) - 1) +#define JOYSTICK_MAX_VALUE ((1L << (JOYSTICK_AXIS_RESOLUTION - 1)) - 1) // configure on input_pin of the joystick_axes array entry to JS_VIRTUAL_AXIS // to prevent it from being read from the ADC. This allows outputing forged axis value. @@ -68,30 +77,56 @@ typedef struct { uint16_t max_digit; } joystick_config_t; -extern joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT]; - -enum joystick_status { - JS_INITIALIZED = 1, - JS_UPDATED, -}; +extern joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT]; typedef struct { uint8_t buttons[(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1]; - - int16_t axes[JOYSTICK_AXES_COUNT]; - uint8_t status : 2; + int16_t axes[JOYSTICK_AXIS_COUNT]; + bool dirty; } joystick_t; -extern joystick_t joystick_status; +extern joystick_t joystick_state; void joystick_task(void); + +/** + * \brief Send the joystick report to the host, if it has been marked as dirty. + */ void joystick_flush(void); +/** + * \brief Set the state of a button, and flush the report. + * + * \param button The index of the button to press, from 0 to 31. + */ void register_joystick_button(uint8_t button); + +/** + * \brief Reset the state of a button, and flush the report. + * + * \param button The index of the button to release, from 0 to 31. + */ void unregister_joystick_button(uint8_t button); +/** + * \brief Sample and process the analog value of the given axis. + * + * \param axis The axis to read. + * + * \return A signed 16-bit integer, where 0 is the resting or mid point. + */ int16_t joystick_read_axis(uint8_t axis); -void joystick_read_axes(void); -void joystick_set_axis(uint8_t axis, int16_t value); + +void joystick_read_axes(void); + +/** + * \brief Set the value of the given axis. + * + * \param axis The axis to set the value of. + * \param value The value to set. + */ +void joystick_set_axis(uint8_t axis, int16_t value); void host_joystick_send(joystick_t *joystick); + +/** \} */ -- cgit v1.2.3