/* * clockworkpi devterm trackball */ #include "keys_io_map.h" #include #include #include #include #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 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 , ExtIntTriggerMode::CHANGE); attachInterrupt(RIGHT_PIN, &interrupt, ExtIntTriggerMode::CHANGE); attachInterrupt(UP_PIN, &interrupt, ExtIntTriggerMode::CHANGE); attachInterrupt(DOWN_PIN, &interrupt, ExtIntTriggerMode::CHANGE); }