summaryrefslogtreecommitdiff
path: root/drivers/sensors/analog_joystick.c
blob: 15b35a45f25a5969e036c9d4fc28a6d7663f51ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/* 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 = !gpio_read_pin(ANALOG_JOYSTICK_CLICK_PIN);
#endif
    return report;
}

void analog_joystick_init(void) {
    gpio_set_pin_input_high(ANALOG_JOYSTICK_X_AXIS_PIN);
    gpio_set_pin_input_high(ANALOG_JOYSTICK_Y_AXIS_PIN);

#ifdef ANALOG_JOYSTICK_CLICK_PIN
    gpio_set_pin_input_high(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
}