analog_joystick.c (5070B)
1 /* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> 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 17 #include "analog_joystick.h" 18 #include "analog.h" 19 #include "gpio.h" 20 #include "wait.h" 21 #include "timer.h" 22 #include <stdlib.h> 23 #include "pointing_device_internal.h" 24 25 const pointing_device_driver_t analog_joystick_pointing_device_driver = { 26 .init = analog_joystick_init, 27 .get_report = analog_joystick_get_report, 28 .set_cpi = NULL, 29 .get_cpi = NULL, 30 }; 31 32 // Set Parameters 33 #ifndef ANALOG_JOYSTICK_AUTO_AXIS 34 uint16_t minAxisValue = ANALOG_JOYSTICK_AXIS_MIN; 35 uint16_t maxAxisValue = ANALOG_JOYSTICK_AXIS_MAX; 36 #else 37 int16_t minAxisValues[2]; 38 int16_t maxAxisValues[2]; 39 #endif 40 41 uint8_t maxCursorSpeed = ANALOG_JOYSTICK_SPEED_MAX; 42 uint8_t speedRegulator = ANALOG_JOYSTICK_SPEED_REGULATOR; // Lower Values Create Faster Movement 43 44 #ifdef ANALOG_JOYSTICK_WEIGHTS 45 int8_t weights[101] = ANALOG_JOYSTICK_WEIGHTS; 46 #endif 47 48 int16_t xOrigin, yOrigin; 49 50 uint16_t lastCursor = 0; 51 52 uint8_t prevValues[2] = {0, 0}; 53 54 int16_t axisCoordinate(pin_t pin, uint16_t origin, uint8_t axis) { 55 int8_t direction; 56 int16_t distanceFromOrigin; 57 int16_t range; 58 59 int16_t position = analogReadPin(pin); 60 61 if (origin == position) { 62 return 0; 63 } else if (origin > position) { 64 distanceFromOrigin = origin - position; 65 #ifdef ANALOG_JOYSTICK_AUTO_AXIS 66 if (position < minAxisValues[axis]) { 67 minAxisValues[axis] = position; 68 } 69 range = origin - minAxisValues[axis]; 70 #else 71 range = origin - minAxisValue; 72 #endif 73 direction = -1; 74 } else { 75 distanceFromOrigin = position - origin; 76 77 #ifdef ANALOG_JOYSTICK_AUTO_AXIS 78 if (position > maxAxisValues[axis]) { 79 maxAxisValues[axis] = position; 80 } 81 range = maxAxisValues[axis] - origin; 82 #else 83 range = maxAxisValue - origin; 84 #endif 85 direction = 1; 86 } 87 88 float percent = (float)distanceFromOrigin / range; 89 int16_t coordinate = (int16_t)(percent * 100); 90 if (coordinate < 0) { 91 return 0; 92 } else if (coordinate > 100) { 93 return 100 * direction; 94 } else { 95 return coordinate * direction; 96 } 97 } 98 99 int8_t axisToMouseComponent(pin_t pin, int16_t origin, uint8_t maxSpeed, uint8_t axis) { 100 int16_t coordinate = axisCoordinate(pin, origin, axis); 101 int8_t result; 102 #ifndef ANALOG_JOYSTICK_WEIGHTS 103 if (coordinate != 0) { 104 float percent = (float)coordinate / 100; 105 result = percent * maxCursorSpeed * (abs(coordinate) / speedRegulator); 106 } else { 107 return 0; 108 } 109 #else 110 result = weights[abs(coordinate)] * (coordinate < 0 ? -1 : 1) * maxCursorSpeed / speedRegulator; 111 #endif 112 113 #ifdef ANALOG_JOYSTICK_CUTOFF 114 uint8_t pv = prevValues[axis]; 115 prevValues[axis] = abs(result); 116 if (pv > abs(result)) { 117 return 0; 118 } 119 #endif 120 121 return result; 122 } 123 124 report_analog_joystick_t analog_joystick_read(void) { 125 report_analog_joystick_t report = {0}; 126 127 if (timer_elapsed(lastCursor) > ANALOG_JOYSTICK_READ_INTERVAL) { 128 lastCursor = timer_read(); 129 report.x = axisToMouseComponent(ANALOG_JOYSTICK_X_AXIS_PIN, xOrigin, maxCursorSpeed, 0); 130 report.y = axisToMouseComponent(ANALOG_JOYSTICK_Y_AXIS_PIN, yOrigin, maxCursorSpeed, 1); 131 } 132 #ifdef ANALOG_JOYSTICK_CLICK_PIN 133 report.button = !gpio_read_pin(ANALOG_JOYSTICK_CLICK_PIN); 134 #endif 135 return report; 136 } 137 138 bool analog_joystick_init(void) { 139 gpio_set_pin_input_high(ANALOG_JOYSTICK_X_AXIS_PIN); 140 gpio_set_pin_input_high(ANALOG_JOYSTICK_Y_AXIS_PIN); 141 142 #ifdef ANALOG_JOYSTICK_CLICK_PIN 143 gpio_set_pin_input_high(ANALOG_JOYSTICK_CLICK_PIN); 144 #endif 145 // Account for drift 146 xOrigin = analogReadPin(ANALOG_JOYSTICK_X_AXIS_PIN); 147 yOrigin = analogReadPin(ANALOG_JOYSTICK_Y_AXIS_PIN); 148 149 #ifdef ANALOG_JOYSTICK_AUTO_AXIS 150 minAxisValues[0] = xOrigin - 100; 151 minAxisValues[1] = yOrigin - 100; 152 maxAxisValues[0] = xOrigin + 100; 153 maxAxisValues[1] = yOrigin + 100; 154 #endif 155 156 return true; 157 } 158 159 report_mouse_t analog_joystick_get_report(report_mouse_t mouse_report) { 160 report_analog_joystick_t data = analog_joystick_read(); 161 162 pd_dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y); 163 164 mouse_report.x = data.x; 165 mouse_report.y = data.y; 166 167 mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, data.button, POINTING_DEVICE_BUTTON1); 168 169 return mouse_report; 170 }