joystick.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /* Copyright 2022
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "joystick.h"
  17. #include "analog.h"
  18. #include "wait.h"
  19. // clang-format off
  20. joystick_t joystick_status = {
  21. .buttons = {0},
  22. .axes = {
  23. #if JOYSTICK_AXES_COUNT > 0
  24. 0
  25. #endif
  26. },
  27. .status = 0
  28. };
  29. // clang-format on
  30. // array defining the reading of analog values for each axis
  31. __attribute__((weak)) joystick_config_t joystick_axes[JOYSTICK_AXES_COUNT] = {};
  32. __attribute__((weak)) void joystick_task(void) {
  33. joystick_read_axes();
  34. }
  35. void joystick_flush(void) {
  36. if ((joystick_status.status & JS_UPDATED) > 0) {
  37. host_joystick_send(&joystick_status);
  38. joystick_status.status &= ~JS_UPDATED;
  39. }
  40. }
  41. void register_joystick_button(uint8_t button) {
  42. joystick_status.buttons[button / 8] |= 1 << (button % 8);
  43. joystick_status.status |= JS_UPDATED;
  44. joystick_flush();
  45. }
  46. void unregister_joystick_button(uint8_t button) {
  47. joystick_status.buttons[button / 8] &= ~(1 << (button % 8));
  48. joystick_status.status |= JS_UPDATED;
  49. joystick_flush();
  50. }
  51. int16_t joystick_read_axis(uint8_t axis) {
  52. // disable pull-up resistor
  53. writePinLow(joystick_axes[axis].input_pin);
  54. // if pin was a pull-up input, we need to uncharge it by turning it low
  55. // before making it a low input
  56. setPinOutput(joystick_axes[axis].input_pin);
  57. wait_us(10);
  58. if (joystick_axes[axis].output_pin != JS_VIRTUAL_AXIS) {
  59. setPinOutput(joystick_axes[axis].output_pin);
  60. writePinHigh(joystick_axes[axis].output_pin);
  61. }
  62. if (joystick_axes[axis].ground_pin != JS_VIRTUAL_AXIS) {
  63. setPinOutput(joystick_axes[axis].ground_pin);
  64. writePinLow(joystick_axes[axis].ground_pin);
  65. }
  66. wait_us(10);
  67. setPinInput(joystick_axes[axis].input_pin);
  68. wait_us(10);
  69. #if defined(ANALOG_JOYSTICK_ENABLE) && (defined(__AVR__) || defined(PROTOCOL_CHIBIOS))
  70. int16_t axis_val = analogReadPin(joystick_axes[axis].input_pin);
  71. #else
  72. // default to resting position
  73. int16_t axis_val = joystick_axes[axis].mid_digit;
  74. #endif
  75. // test the converted value against the lower range
  76. int32_t ref = joystick_axes[axis].mid_digit;
  77. int32_t range = joystick_axes[axis].min_digit;
  78. int32_t ranged_val = ((axis_val - ref) * -JOYSTICK_RESOLUTION) / (range - ref);
  79. if (ranged_val > 0) {
  80. // the value is in the higher range
  81. range = joystick_axes[axis].max_digit;
  82. ranged_val = ((axis_val - ref) * JOYSTICK_RESOLUTION) / (range - ref);
  83. }
  84. // clamp the result in the valid range
  85. ranged_val = ranged_val < -JOYSTICK_RESOLUTION ? -JOYSTICK_RESOLUTION : ranged_val;
  86. ranged_val = ranged_val > JOYSTICK_RESOLUTION ? JOYSTICK_RESOLUTION : ranged_val;
  87. return ranged_val;
  88. }
  89. void joystick_read_axes() {
  90. #if JOYSTICK_AXES_COUNT > 0
  91. for (int i = 0; i < JOYSTICK_AXES_COUNT; ++i) {
  92. if (joystick_axes[i].input_pin == JS_VIRTUAL_AXIS) {
  93. continue;
  94. }
  95. joystick_set_axis(i, joystick_read_axis(i));
  96. }
  97. joystick_flush();
  98. #endif
  99. }
  100. void joystick_set_axis(uint8_t axis, int16_t value) {
  101. if (value != joystick_status.axes[axis]) {
  102. joystick_status.axes[axis] = value;
  103. joystick_status.status |= JS_UPDATED;
  104. }
  105. }