123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- /*
- * 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);
- }
- 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;
- 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*){
- 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);
-
- }
|