trackball.ino 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /*
  2. * clockworkpi devterm trackball
  3. */
  4. #include "keys_io_map.h"
  5. #include <stdint.h>
  6. #include <stdbool.h>
  7. #include <string.h>
  8. #include <USBComposite.h>
  9. #include "trackball.h"
  10. #include "ratemeter.h"
  11. #include "glider.h"
  12. #include "math.h"
  13. enum Axis: uint8_t {
  14. AXIS_X,
  15. AXIS_Y,
  16. AXIS_NUM,
  17. };
  18. static int8_t distances[AXIS_NUM];
  19. static RateMeter rateMeter[AXIS_NUM];
  20. static Glider glider[AXIS_NUM];
  21. static const int8_t WHEEL_DENOM = 2;
  22. static int8_t wheelBuffer;
  23. static float rateToVelocityCurve(float input) {
  24. return std::pow(std::abs(input) / 50, 1.4);
  25. }
  26. template<Axis AXIS, int8_t Direction>
  27. static void interrupt() {
  28. distances[AXIS] += Direction;
  29. rateMeter[AXIS].onInterrupt();
  30. glider[AXIS].setDirection(Direction);
  31. const auto rx = rateMeter[AXIS_X].rate();
  32. const auto ry = rateMeter[AXIS_Y].rate();
  33. const auto rate = std::sqrt(rx * rx + ry * ry);
  34. const auto ratio = rateToVelocityCurve(rate) / rate;
  35. const auto vx = rx * ratio;
  36. const auto vy = ry * ratio;
  37. if (AXIS == AXIS_X) {
  38. glider[AXIS_X].update(vx, rateMeter[AXIS_X].delta());
  39. glider[AXIS_Y].updateSpeed(vy);
  40. } else {
  41. glider[AXIS_X].updateSpeed(vx);
  42. glider[AXIS_Y].update(vy, rateMeter[AXIS_Y].delta());
  43. }
  44. }
  45. void trackball_task(DEVTERM*dv) {
  46. int8_t x = 0, y = 0, w = 0;
  47. noInterrupts();
  48. rateMeter[AXIS_X].tick(dv->delta);
  49. rateMeter[AXIS_Y].tick(dv->delta);
  50. const auto mode = dv->state->moveTrackball();
  51. switch(mode){
  52. case TrackballMode::Mouse: {
  53. const auto rX = glider[AXIS_X].glide(dv->delta);
  54. const auto rY = glider[AXIS_Y].glide(dv->delta);
  55. x = rX.value;
  56. y = rY.value;
  57. if (rX.stopped) {
  58. glider[AXIS_Y].stop();
  59. }
  60. if (rY.stopped) {
  61. glider[AXIS_Y].stop();
  62. }
  63. break;
  64. }
  65. case TrackballMode::Wheel: {
  66. wheelBuffer += distances[AXIS_Y];
  67. w = wheelBuffer / WHEEL_DENOM;
  68. wheelBuffer -= w * WHEEL_DENOM;
  69. break;
  70. }
  71. }
  72. distances[AXIS_X] = 0;
  73. distances[AXIS_Y] = 0;
  74. interrupts();
  75. if(x !=0 || y != 0 || -w!=0) {
  76. dv->Mouse->move(x, y, -w);
  77. }
  78. }
  79. void trackball_init(DEVTERM*){
  80. pinMode(LEFT_PIN, INPUT);
  81. pinMode(UP_PIN, INPUT);
  82. pinMode(RIGHT_PIN, INPUT);
  83. pinMode(DOWN_PIN, INPUT);
  84. attachInterrupt(LEFT_PIN, &interrupt<AXIS_X, -1>, ExtIntTriggerMode::CHANGE);
  85. attachInterrupt(RIGHT_PIN, &interrupt<AXIS_X, 1>, ExtIntTriggerMode::CHANGE);
  86. attachInterrupt(UP_PIN, &interrupt<AXIS_Y, -1>, ExtIntTriggerMode::CHANGE);
  87. attachInterrupt(DOWN_PIN, &interrupt<AXIS_Y, 1>, ExtIntTriggerMode::CHANGE);
  88. }