qmk_firmware/drivers/sensors/analog_joystick.c

145 lines
4.2 KiB
C

/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "analog_joystick.h"
#include "analog.h"
#include "gpio.h"
#include "wait.h"
#include "timer.h"
#include <stdlib.h>
// Set Parameters
#ifndef ANALOG_JOYSTICK_AUTO_AXIS
uint16_t minAxisValue = ANALOG_JOYSTICK_AXIS_MIN;
uint16_t maxAxisValue = ANALOG_JOYSTICK_AXIS_MAX;
#else
int16_t minAxisValues[2];
int16_t maxAxisValues[2];
#endif
uint8_t maxCursorSpeed = ANALOG_JOYSTICK_SPEED_MAX;
uint8_t speedRegulator = ANALOG_JOYSTICK_SPEED_REGULATOR; // Lower Values Create Faster Movement
#ifdef ANALOG_JOYSTICK_WEIGHTS
int8_t weights[101] = ANALOG_JOYSTICK_WEIGHTS;
#endif
int16_t xOrigin, yOrigin;
uint16_t lastCursor = 0;
uint8_t prevValues[2] = {0, 0};
int16_t axisCoordinate(pin_t pin, uint16_t origin, uint8_t axis) {
int8_t direction;
int16_t distanceFromOrigin;
int16_t range;
int16_t position = analogReadPin(pin);
if (origin == position) {
return 0;
} else if (origin > position) {
distanceFromOrigin = origin - position;
#ifdef ANALOG_JOYSTICK_AUTO_AXIS
if (position < minAxisValues[axis]) {
minAxisValues[axis] = position;
}
range = origin - minAxisValues[axis];
#else
range = origin - minAxisValue;
#endif
direction = -1;
} else {
distanceFromOrigin = position - origin;
#ifdef ANALOG_JOYSTICK_AUTO_AXIS
if (position > maxAxisValues[axis]) {
maxAxisValues[axis] = position;
}
range = maxAxisValues[axis] - origin;
#else
range = maxAxisValue - origin;
#endif
direction = 1;
}
float percent = (float)distanceFromOrigin / range;
int16_t coordinate = (int16_t)(percent * 100);
if (coordinate < 0) {
return 0;
} else if (coordinate > 100) {
return 100 * direction;
} else {
return coordinate * direction;
}
}
int8_t axisToMouseComponent(pin_t pin, int16_t origin, uint8_t maxSpeed, uint8_t axis) {
int16_t coordinate = axisCoordinate(pin, origin, axis);
int8_t result;
#ifndef ANALOG_JOYSTICK_WEIGHTS
if (coordinate != 0) {
float percent = (float)coordinate / 100;
result = percent * maxCursorSpeed * (abs(coordinate) / speedRegulator);
} else {
return 0;
}
#else
result = weights[abs(coordinate)] * (coordinate < 0 ? -1 : 1) * maxCursorSpeed / speedRegulator;
#endif
#ifdef ANALOG_JOYSTICK_CUTOFF
uint8_t pv = prevValues[axis];
prevValues[axis] = abs(result);
if (pv > abs(result)) {
return 0;
}
#endif
return result;
}
report_analog_joystick_t analog_joystick_read(void) {
report_analog_joystick_t report = {0};
if (timer_elapsed(lastCursor) > ANALOG_JOYSTICK_READ_INTERVAL) {
lastCursor = timer_read();
report.x = axisToMouseComponent(ANALOG_JOYSTICK_X_AXIS_PIN, xOrigin, maxCursorSpeed, 0);
report.y = axisToMouseComponent(ANALOG_JOYSTICK_Y_AXIS_PIN, yOrigin, maxCursorSpeed, 1);
}
#ifdef ANALOG_JOYSTICK_CLICK_PIN
report.button = !readPin(ANALOG_JOYSTICK_CLICK_PIN);
#endif
return report;
}
void analog_joystick_init(void) {
#ifdef ANALOG_JOYSTICK_CLICK_PIN
setPinInputHigh(ANALOG_JOYSTICK_CLICK_PIN);
#endif
// Account for drift
xOrigin = analogReadPin(ANALOG_JOYSTICK_X_AXIS_PIN);
yOrigin = analogReadPin(ANALOG_JOYSTICK_Y_AXIS_PIN);
#ifdef ANALOG_JOYSTICK_AUTO_AXIS
minAxisValues[0] = xOrigin - 100;
minAxisValues[1] = yOrigin - 100;
maxAxisValues[0] = xOrigin + 100;
maxAxisValues[1] = yOrigin + 100;
#endif
}