qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

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 }