mirror of
https://github.com/clockworkpi/uConsole.git
synced 2025-12-12 18:18:50 +01:00
131 lines
2.8 KiB
C++
131 lines
2.8 KiB
C++
/*
|
|
* clockworkpi devterm trackball
|
|
*/
|
|
#include "keys_io_map.h"
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
#include <USBComposite.h>
|
|
|
|
|
|
#include "trackball.h"
|
|
|
|
#include "ratemeter.h"
|
|
#include "glider.h"
|
|
#include "math.h"
|
|
|
|
|
|
|
|
enum Axis: uint8_t {
|
|
AXIS_X,
|
|
AXIS_Y,
|
|
AXIS_NUM,
|
|
};
|
|
static TrackballMode lastMode;
|
|
static int8_t distances[AXIS_NUM];
|
|
static RateMeter rateMeter[AXIS_NUM];
|
|
static Glider glider[AXIS_NUM];
|
|
|
|
static const int8_t WHEEL_DENOM = 2;
|
|
static int8_t wheelBuffer;
|
|
|
|
static float rateToVelocityCurve(float input) {
|
|
//return std::pow(std::abs(input) / 50, 1.4);
|
|
return std::abs(input) / 30;
|
|
}
|
|
|
|
template<Axis AXIS, int8_t Direction >
|
|
static void interrupt( ) {
|
|
distances[AXIS] += Direction;
|
|
rateMeter[AXIS].onInterrupt();
|
|
glider[AXIS].setDirection(Direction);
|
|
|
|
const auto rx = rateMeter[AXIS_X].rate();
|
|
const auto ry = rateMeter[AXIS_Y].rate();
|
|
|
|
const auto rate = std::sqrt(rx * rx + ry * ry);
|
|
const auto ratio = rateToVelocityCurve(rate) / rate;
|
|
|
|
const auto vx = rx * ratio;
|
|
const auto vy = ry * ratio;
|
|
|
|
if (AXIS == AXIS_X) {
|
|
glider[AXIS_X].update(vx, std::sqrt(rateMeter[AXIS_X].delta()));
|
|
glider[AXIS_Y].updateSpeed(vy);
|
|
|
|
} else {
|
|
glider[AXIS_X].updateSpeed(vx);
|
|
glider[AXIS_Y].update(vy, std::sqrt(rateMeter[AXIS_Y].delta()));
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void trackball_task(DEVTERM*dv) {
|
|
int8_t x = 0, y = 0, w = 0;
|
|
noInterrupts();
|
|
const auto mode = dv->state->moveTrackball();
|
|
if (lastMode != mode) {
|
|
rateMeter[AXIS_X].expire();
|
|
rateMeter[AXIS_Y].expire();
|
|
wheelBuffer = 0;
|
|
}
|
|
else {
|
|
rateMeter[AXIS_X].tick(dv->delta);
|
|
rateMeter[AXIS_Y].tick(dv->delta);
|
|
}
|
|
lastMode = mode;
|
|
|
|
switch(mode){
|
|
case TrackballMode::Mouse: {
|
|
const auto rX = glider[AXIS_X].glide(dv->delta);
|
|
const auto rY = glider[AXIS_Y].glide(dv->delta);
|
|
x = rX.value;
|
|
y = rY.value;
|
|
if (rX.stopped) {
|
|
glider[AXIS_Y].stop();
|
|
}
|
|
if (rY.stopped) {
|
|
glider[AXIS_Y].stop();
|
|
}
|
|
|
|
break;
|
|
}
|
|
case TrackballMode::Wheel: {
|
|
wheelBuffer += distances[AXIS_Y];
|
|
w = wheelBuffer / WHEEL_DENOM;
|
|
wheelBuffer -= w * WHEEL_DENOM;
|
|
if(w != 0){
|
|
dv->state->setScrolled();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
distances[AXIS_X] = 0;
|
|
distances[AXIS_Y] = 0;
|
|
interrupts();
|
|
|
|
if(x !=0 || y != 0 || -w!=0) {
|
|
dv->Mouse->move(x, y, -w);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void trackball_init(DEVTERM*dv){
|
|
|
|
pinMode(LEFT_PIN, INPUT);
|
|
pinMode(UP_PIN, INPUT);
|
|
pinMode(RIGHT_PIN, INPUT);
|
|
pinMode(DOWN_PIN, INPUT);
|
|
|
|
attachInterrupt(LEFT_PIN, &interrupt<AXIS_X,-1> , ExtIntTriggerMode::CHANGE);
|
|
attachInterrupt(RIGHT_PIN, &interrupt<AXIS_X, 1>, ExtIntTriggerMode::CHANGE);
|
|
attachInterrupt(UP_PIN, &interrupt<AXIS_Y, -1>, ExtIntTriggerMode::CHANGE);
|
|
attachInterrupt(DOWN_PIN, &interrupt<AXIS_Y, 1>, ExtIntTriggerMode::CHANGE);
|
|
|
|
}
|